#ifndef __CYCLEDBUFFER_HPP__
#define __CYCLEDBUFFER_HPP__

#include "interlock.h"
#include "boost/asio.hpp"

namespace pnNetlib
{
	template<typename T>
	class pnCycledBuffer
	{
	public:
		typedef T       data_type;

	private:
		typename data_type*      m_pArray;

		long    m_nCount;
		long    m_nValidReadLength;
		long    m_nReadIndex;
		long    m_nWriteIndex;

	public:
		pnCycledBuffer(long count_of_elem);
		~pnCycledBuffer();

	public:
		///@brief   get total length of buffer(read-only)
		const long   total_legnth() const;

		///@brief   get the valid read buffer length
		const long   valid_read_length() const;

		///@brief   get the valid write buffer length
		const long   valid_write_length() const;

	public:///paral
		///@brief    get the write pointer
		///retval    mutable_buffers_1
		boost::asio::mutable_buffers_1    get_write_buffer(long count_of_elem);

		///@brief    commit write
		///retval    void
		void   commit_buffer(long count_of_elem);

		///@brief    get the read pointer
		///retval    mutable_buffers_1
		boost::asio::mutable_buffers_1    get_read_ptr(long count_of_elem);

		///@brief   cast the content
		///param[in]    count_of_elem      how many elem to pop
		///retval   void      point to the first elem's address of the poping array
		void   cast_buffer(long count_of_elem);
	};

	/*********************************************************************************************************************************************/
	template<typename T>
	pnCycledBuffer<T>::pnCycledBuffer(long count_of_elem):
	m_nCount(count_of_elem),
	m_nValidReadLength(0),
	m_nReadIndex(0),
	m_nWriteIndex(0),
	m_pArray(new T[count_of_elem])
	{

	}

	/*********************************************************************************************************************************************/
	template<typename T>
	pnCycledBuffer<T>::~pnCycledBuffer()
	{
		delete [] m_pArray;
	}

	/*********************************************************************************************************************************************/
	template<typename T>
	inline
	const
	long
	pnCycledBuffer<T>::total_legnth() const
	{
		return m_nCount;
	}
	/*********************************************************************************************************************************************/
	template<typename T>
	const
	long
	pnCycledBuffer<T>::valid_write_length() const
	{
		return m_nCount - m_nValidReadLength;
	}

	/*********************************************************************************************************************************************/
	template<typename T>
	const
	long
	pnCycledBuffer<T>::valid_read_length() const
	{
		return m_nValidReadLength;
	}

	/*********************************************************************************************************************************************/
	template<typename T>
	boost::asio::mutable_buffers_1
	pnCircleBuffer<T>::get_write_buffer(long count_of_elem)
	{
		if(m_nWriteIndex + count_of_elem <= m_nCount)
			return boost::asio::buffer(&m_pArray[m_nWriteIndex], count_of_elem * sizeof(T) );
		else if(m_nReadIndex >=  count_of_elem)
			return boost::asio::buffer(&m_pArray[0], count_of_elem * sizeof(T) );
		else
			return boost::asio::null_buffers();
	}

	/*********************************************************************************************************************************************/
	template<typename T>
	void
	pnCircleBuffer<T>::commit_buffer(long count_of_elem)
	{
		long new_index = m_nWriteIndex;
		if(m_nWriteIndex + count_of_elem <= m_nCount)
		{
			new_index = (m_nWriteIndex + count_of_elem) % m_nCount;
			inter_lock::exchange(&m_nWriteIndex, new_index);
		}
		else
		{
			new_index = count_of_elem;
			inter_lock::exchange(&m_nWriteIndex, new_index);
		}
	}

	/*********************************************************************************************************************************************/
	template<typename T>
	boost::asio::mutable_buffers_1
	pnCircleBuffer<T>::get_read_ptr(long count_of_elem)
	{
        if(m_nReadIndex + count_of_elem <= m_nCount)
			return boost::asio::buffer(&m_pArray[m_nReadIndex], count_of_elem * sizeof(T) );
		else if(m_nWriteIndex >=  count_of_elem)
			return boost::asio::buffer(&m_pArray[0], count_of_elem * sizeof(T) );
		else
			return boost::asio::null_buffers();
	}

	/*********************************************************************************************************************************************/
	template<typename T>
	void
	pnCircleBuffer<T>::cast_buffer(long count_of_elem)
	{
		long new_index = m_nReadIndex;
		if(m_nReadIndex + count_of_elem <= m_nCount)
		{
			new_index = (m_nReadIndex + count_of_elem) % m_nCount;
			inter_lock::exchange(&m_nReadIndex, new_index);
		}
		else
		{
			new_index = count_of_elem;
			inter_lock::exchange(&m_nReadIndex, new_index);
		}
	}

	/*********************************************************************************************************************************************/

};

#endif